Skip to contentMethod: waitForEvent(VierConnectsPlayer, VierConnectsState)
      1: /*
2:  * Copyright © 2021-2023 Fachhochschule für die Wirtschaft (FHDW) Hannover
3:  *
4:  * This file is part of ipspiel24-VierConnects-gui.
5:  *
6:  * ipspiel24-VierConnects-gui is free software: you can redistribute it and/or modify it under
7:  * the terms of the GNU General Public License as published by the Free Software
8:  * Foundation, either version 3 of the License, or (at your option) any later
9:  * version.
10:  *
11:  * ipspiel24-VierConnects-gui is distributed in the hope that it will be useful, but WITHOUT
12:  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13:  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14:  * details.
15:  *
16:  * You should have received a copy of the GNU General Public License along with
17:  * ipspiel24-VierConnects-gui. If not, see <http://www.gnu.org/licenses/>.
18:  */
19: package de.fhdw.gaming.ipspiel24.VierConnects.gui.impl;
20: 
21: import java.util.ArrayList;
22: import java.util.Collection;
23: import java.util.LinkedHashMap;
24: import java.util.List;
25: import java.util.Map;
26: import java.util.concurrent.atomic.AtomicReference;
27: 
28: import de.fhdw.gaming.ipspiel24.VierConnects.core.domain.VierConnectsBoard;
29: import de.fhdw.gaming.ipspiel24.VierConnects.core.domain.VierConnectsField;
30: import de.fhdw.gaming.ipspiel24.VierConnects.core.domain.VierConnectsFieldState;
31: import de.fhdw.gaming.ipspiel24.VierConnects.core.domain.VierConnectsPlayer;
32: import de.fhdw.gaming.ipspiel24.VierConnects.core.domain.VierConnectsPosition;
33: import de.fhdw.gaming.ipspiel24.VierConnects.core.domain.VierConnectsState;
34: import de.fhdw.gaming.ipspiel24.VierConnects.gui.VierConnectsBoardEventProvider;
35: import de.fhdw.gaming.ipspiel24.VierConnects.gui.event.VierConnectsBoardEvent;
36: import de.fhdw.gaming.ipspiel24.VierConnects.gui.event.VierConnectsMakeMoveBoardEvent;
37: import javafx.application.Platform;
38: import javafx.scene.Cursor;
39: import javafx.scene.input.MouseButton;
40: import javafx.scene.input.MouseEvent;
41: 
42: /**
43:  * Implements user interaction with a VierConnects board.
44:  */
45: final class VierConnectsBoardEventProviderImpl implements VierConnectsBoardEventProvider {
46: 
47:     /**
48:      * The associated {@link VierConnectsBoardView}.
49:      */
50:     private final VierConnectsBoardView boardView;
51: 
52:     /**
53:      * Constructor.
54:      *
55:      * @param boardView The associated {@link VierConnectsBoardView}.
56:      */
57:     VierConnectsBoardEventProviderImpl(final VierConnectsBoardView boardView) {
58:         this.boardView = boardView;
59:     }
60: 
61:     @Override
62:     public VierConnectsBoardEvent waitForEvent(final VierConnectsPlayer player, final VierConnectsState state) {
63:         final Map<VierConnectsPosition, VierConnectsFieldView> emptyFieldViews = new LinkedHashMap<>();
64:•        for (final Map.Entry<VierConnectsPosition, ? extends VierConnectsField> entry : state.getBoard()
65:                 .getFieldsBeing(VierConnectsFieldState.EMPTY).entrySet()) {
66:             emptyFieldViews.put(entry.getKey(), this.boardView.getFieldView(entry.getKey()).orElseThrow());
67:         }
68: 
69:         final AtomicReference<VierConnectsBoardEvent> event = new AtomicReference<>();
70:         final Runnable cleanUp;
71:•        if (emptyFieldViews.isEmpty()) {
72:             final List<VierConnectsFieldView> fieldViews = this.setupInactiveFields(state.getBoard());
73:             cleanUp = () -> this.cleanUpFields(fieldViews);
74:         } else {
75:             this.setupActiveFields(emptyFieldViews, event);
76:             cleanUp = () -> this.cleanUpFields(emptyFieldViews.values());
77:         }
78: 
79:         try {
80:             this.boardView.getUserInputSemaphore().acquire();
81:             return event.get();
82:         } catch (final InterruptedException e) {
83:             return null;
84:         } finally {
85:             Platform.runLater(cleanUp);
86:         }
87:     }
88: 
89:     /**
90:      * Sets up the fields when a move is possible (and hence the set of empty fields is not empty).
91:      *
92:      * @param emptyFieldViews The non-empty set of views for active fields.
93:      * @param event           The event to be set when the user selects an active field.
94:      */
95:     private void setupActiveFields(final Map<VierConnectsPosition, VierConnectsFieldView> emptyFieldViews,
96:             final AtomicReference<VierConnectsBoardEvent> event) {
97:         for (final Map.Entry<VierConnectsPosition, VierConnectsFieldView> entry : emptyFieldViews.entrySet()) {
98:             final VierConnectsPosition position = entry.getKey();
99:             final VierConnectsFieldView fieldView = entry.getValue();
100:             Platform.runLater(() -> {
101:                 fieldView.setCursor(Cursor.CROSSHAIR);
102:                 fieldView.setHighlighted(true);
103:                 fieldView.setOnMouseClicked((final MouseEvent mouseEvent) -> {
104:                     if (mouseEvent.getButton() == MouseButton.PRIMARY) {
105:                         event.set(new VierConnectsMakeMoveBoardEvent(position));
106:                         this.boardView.getUserInputSemaphore().release();
107:                     }
108:                 });
109:             });
110:         }
111:     }
112: 
113:     /**
114:      * Sets up the fields when no move is possible (and hence the set of empty fields is empty).
115:      *
116:      * @param board The Vier Connects board.
117:      * @return A list of all field views on the board.
118:      */
119:     private List<VierConnectsFieldView> setupInactiveFields(final VierConnectsBoard board) {
120:         final List<VierConnectsField> fields = new ArrayList<>();
121:         board.getFields().forEach((final List<? extends VierConnectsField> list) -> fields.addAll(list));
122: 
123:         final List<VierConnectsFieldView> fieldViews = new ArrayList<>();
124:         for (final VierConnectsField field : fields) {
125:             final VierConnectsFieldView fieldView = this.boardView.getFieldView(field.getPosition()).orElseThrow();
126:             fieldViews.add(fieldView);
127:             Platform.runLater(() -> {
128:                 fieldView.setCursor(Cursor.CLOSED_HAND);
129:                 fieldView.setOnMouseClicked(null);
130:             });
131:         }
132: 
133:         return fieldViews;
134:     }
135: 
136:     /**
137:      * Cleans up after user interaction by resetting mouse cursors and removing event handlers.
138:      *
139:      * @param fieldViews The modified field views.
140:      */
141:     private void cleanUpFields(final Collection<? extends VierConnectsFieldView> fieldViews) {
142:         for (final VierConnectsFieldView fieldView : fieldViews) {
143:             fieldView.setCursor(Cursor.DEFAULT);
144:             fieldView.setHighlighted(false);
145:             fieldView.setOnMouseClicked(null);
146:         }
147:     }
148: 
149:     @Override
150:     public void cancelWaiting() {
151:         this.boardView.getUserInputSemaphore().release();
152:     }
153: }